home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.1_SDK_DR3 / Source / FWiX / FWiXApp / FWiXdrag.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-17  |  22.7 KB  |  878 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWXDrag.c
  3.  
  4.     Contains:    Software to handle Finder drag copies onto FireWire File Exchange icons.
  5.  
  6.     Version:    1.0
  7.  
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (DCB)    Clinton Bauder
  23.         (jkl)    Jay Lloyd
  24.  
  25.     Change History (most recent first):
  26.  
  27.       <FW18>      4/8/99    jkl        More interface cleanup.
  28.       <FW17>    12/19/98    DCB        More cleanup for SDK.
  29.       <FW16>      2/1/98    jkl        Include Errors.h.
  30.       <FW15>     1/15/98    jkl        Update for new headers.
  31.       <FW14>     6/19/97    jkl        Made SendFSSpecListToSelf available globally for send
  32.                                     AppleScript command.
  33.       <FW13>     5/16/97    jkl        Disposed of region handle in HandleDragTracking.
  34.       <FW12>      5/7/97    jkl        Updated data structure field names.
  35.       <FW11>     4/29/97    jkl        Made sure node drag hiliting is clipped within the scroll bars
  36.                                     and window.
  37.       <FW10>     3/18/97    jkl        Changed drag hiliting to hilite node icon and name.
  38.        <FW9>     2/27/97    jkl        Updated drag receive routine to handle window scrolling.
  39.        <FW8>     2/19/97    jkl        Fixed a problem with GetNodeInfo returning bad error message.
  40.        <FW7>      2/2/97    jkl        Corrected the DragReceive routine to only recognize a drop in a
  41.                                     node rectangle.
  42.        <FW6>     1/27/97    jkl        Changed the HandleFSItems routine to call a routine to add the
  43.                                     items to a send check queue, instead of calling a preflight
  44.                                     check and attempting send..
  45.        <FW5>     1/16/97    jkl        Added user interface features for alpha candidate. Changed
  46.                                     window handling to normal window behavior and updated drag
  47.                                     tracking for this.
  48.        <FW4>      1/8/97    ES        Changed to use FWX nodes instead of FWX drivers.
  49.        <FW3>    11/13/96    jkl        Added accessor routines to get receive node name and node info
  50.                                     record.
  51.        <FW2>    10/31/96    jkl        Added code to start check for receiver node
  52.                                     being able to handle copy. Added support for
  53.                                     multiple file/folder drops. Changed drag
  54.                                     acceptance to not accept drag if copy in progress.
  55.        <FW1>     10/2/96    jkl        initial check-in, based on DTS FinderDrag
  56. */
  57.  
  58. #include <Types.h>
  59. #include <Errors.h>
  60. #include <QuickDraw.h>
  61. #include <Files.h>
  62. #include <Controls.h>
  63. #include <AppleEvents.h>
  64. #include <Processes.h>
  65. #include <Drag.h>
  66. #include <Windows.h>
  67. #include <Devices.h>
  68. #include <Timer.h>
  69. #include <Icons.h>
  70.  
  71. #include "FWiX.h"
  72. #include "FWiXmain.h"
  73. #include "FWiXdrag.h"
  74.  
  75. #include <stdio.h>
  76. extern char  debugStr[256];
  77. static pascal void FWDebugStr(
  78.     ConstStr255Param            debuggerMsg)
  79. {
  80. #ifdef FW_DEBUG_BUILD
  81. #if FW_DEBUG_BUILD
  82.     DebugStr (debuggerMsg);
  83. #endif
  84. #endif
  85. }
  86.  
  87. //////////////////////////////////////////////////////////////////////////////
  88. //
  89. // Internal procedure prototypes.
  90. //
  91.  
  92. OSErr InstallDragHandlers (void);    
  93.  
  94. void RemoveDragHandlers (void);
  95.     
  96. static Boolean MouseIsInContentRgn (
  97.     DragReference            theDrag,
  98.     WindowPtr                pWin);
  99.  
  100. static Boolean DragItemsAreAcceptable (
  101.     DragReference            theDrag);
  102.     
  103. static pascal OSErr HandleDragTracking (
  104.     DragTrackingMessage        theMessage,
  105.     WindowPtr                pWin,
  106.     void                    *handlerRefCon,
  107.     DragReference            theDrag);
  108.  
  109. static pascal OSErr HandleDragReceive (
  110.     WindowPtr                pWin,
  111.     void                    *handlerRefCon, 
  112.     DragReference            theDrag);
  113.     
  114. OSErr GetNodeInfo (
  115.     FWXNodeID                nodeID,
  116.     RecvNodePtr                *pRecvNode);
  117.  
  118. OSErr GetNodeDragRect (
  119.     WindowPtr            pWin,
  120.     SInt16                spaceIndex,
  121.     Rect                *iconRect,
  122.     Rect                *textRect);
  123.     
  124. OSErr GetNodeName (
  125.     WindowPtr            pWin,
  126.     SInt16                spaceIndex,
  127.     StringPtr            *pString);
  128.     
  129. static SInt16 WhichRecvNode (
  130.     WindowPtr            pWin,
  131.     Point                localPt);
  132.     
  133. static void GetNodeIDFromIndex(
  134.     SInt16                nodeIndex,
  135.     FWXNodeID            *whichNode,
  136.     WindowPtr            pWin);
  137.  
  138. static void SendDropInWindowRecvNode (
  139.     WindowPtr            pWin,
  140.     DragReference        theDrag,
  141.     FSSpecPtr            pFSSpecList,
  142.     UInt16                numInList);
  143.  
  144. pascal OSErr HandleAEFileSpecList (
  145.     AppleEvent            *pAEvent,
  146.     AppleEvent             *pReply,
  147.     SInt32                refCon);
  148.     
  149. static void HandleDragHilite (
  150.     SInt16                theMessage,
  151.     Rect                *iconRect,
  152.     Rect                *textRect);
  153.         
  154. //////////////////////////////////////////////////////////////////////////////
  155. //
  156. // External procedure prototypes.
  157. //
  158.  
  159. extern OSErr HandleFSItem (
  160.     FSSpecPtr            pFSItem,
  161.     FWXNodeID            whichNode);
  162.  
  163. //////////////////////////////////////////////////////////////////////////////
  164. //
  165. //    Globals
  166. //
  167. extern FWXAppDataPtr gpFWXAppData;
  168.  
  169. //////////////////////////////////////////////////////////////////////////////
  170. //
  171. //    InstallDragHandlers
  172. //
  173. //    InstallDragHandlers attaches tracking and receive handlers to our
  174. //    application.
  175. //    
  176. //
  177.  
  178. OSErr InstallDragHandlers (void)
  179. {
  180.     DragTrackingHandlerUPP        pDragTracker = nil;
  181.     DragReceiveHandlerUPP        pDragReceiver = nil;
  182.     OSErr                         err = noErr;
  183.     
  184.     gpFWXAppData->dragReceiveHandlerInstalled = false;
  185.     gpFWXAppData->dragTrackingHandlerInstalled = false;
  186.     
  187.     //    Create and install the drag tracker
  188.     pDragTracker = NewDragTrackingHandlerProc(HandleDragTracking);
  189.     if (pDragTracker != nil) {
  190.         //    We allocated the procpointer, install it.
  191.         err = InstallTrackingHandler(pDragTracker, nil, nil);
  192.     
  193.         if (err == noErr) {
  194.             //    We installed the drag tracker.
  195.             gpFWXAppData->dragTrackingHandler = pDragTracker;
  196.             gpFWXAppData->dragTrackingHandlerInstalled = true;
  197.         } else {
  198.             //    The drag tracker was allocated but not installed,
  199.             //    dispose of the routine descriptor.
  200.             DisposeRoutineDescriptor(pDragTracker);
  201.             return err;
  202.         }
  203.     } else {
  204.         //    We could not allocate the proc pointer
  205.         return memFullErr;
  206.     }
  207.     
  208.     //    Create and install the drag receiver. If we got this far,
  209.     //    the drag tracker is installed.
  210.     pDragReceiver = NewDragReceiveHandlerProc(HandleDragReceive);
  211.     if (pDragReceiver != nil) {
  212.         //    We allocated the procpointer, install it.
  213.         err = InstallReceiveHandler(pDragReceiver, nil, nil);
  214.     
  215.         if (err == noErr) {
  216.             //    We installed the drag receiver.
  217.             gpFWXAppData->dragReceiveHandler = pDragReceiver;
  218.             gpFWXAppData->dragReceiveHandlerInstalled = true;
  219.         } else {
  220.             //    The drag receiver was allocated but not installed,
  221.             //    dispose of the routine descriptor, clean up the tracker.
  222.             DisposeRoutineDescriptor(pDragReceiver);
  223.             RemoveTrackingHandler(pDragTracker, nil);
  224.             DisposeRoutineDescriptor(pDragTracker);
  225.             gpFWXAppData->dragTrackingHandlerInstalled = false;
  226.             return err;
  227.         }
  228.     } else {
  229.         //    We could not allocate the proc pointer, clean up the tracker.
  230.         RemoveTrackingHandler(pDragTracker, nil);
  231.         DisposeRoutineDescriptor(pDragTracker);
  232.         gpFWXAppData->dragTrackingHandlerInstalled = false;
  233.         return memFullErr;
  234.     }
  235.             
  236.     return err;
  237. }
  238.  
  239.  
  240. //////////////////////////////////////////////////////////////////////////////
  241. //
  242. //    RemoveDragHandlers
  243. //
  244. //    Remove the drag handlers from a window prior to closing the window.
  245. //
  246.  
  247. void RemoveDragHandlers (void)
  248. {    
  249.     if (gpFWXAppData->dragReceiveHandlerInstalled) {
  250.         RemoveReceiveHandler(gpFWXAppData->dragReceiveHandler , nil);
  251.         DisposeRoutineDescriptor(gpFWXAppData->dragReceiveHandler);
  252.     }
  253.     
  254.     if (gpFWXAppData->dragTrackingHandlerInstalled) {
  255.         RemoveTrackingHandler(gpFWXAppData->dragTrackingHandler, nil);
  256.         DisposeRoutineDescriptor(gpFWXAppData->dragTrackingHandler);
  257.     }
  258. }
  259.  
  260.  
  261. //////////////////////////////////////////////////////////////////////////////
  262. //
  263. //    MouseInContentRgn
  264. //
  265. //    returns true if the mouse is in the content area of the window
  266. //    (not necessarily in the visible rgn)
  267. //
  268.  
  269. static Boolean MouseIsInContentRgn (
  270.     DragReference            theDrag,
  271.     WindowPtr                pWin)
  272. {
  273.     Point                    mousePt;
  274.     
  275.     GetDragMouse(theDrag, &mousePt, nil);
  276.     
  277.     return PtInRgn(mousePt, ((WindowPeek) pWin)->contRgn);
  278. }
  279.  
  280.  
  281. //////////////////////////////////////////////////////////////////////////////
  282. //
  283. //    DragItemsAreAcceptable
  284. //
  285. //    Returns true if the contents (data) of the drag
  286. //    are acceptable. Its a file or folder.
  287. //
  288. //    Called by the tracking and receive handlers
  289. //
  290.  
  291. static Boolean DragItemsAreAcceptable(
  292.     DragReference        theDrag)
  293. {
  294.     OSErr                err;
  295.     UInt16                numItems;
  296.     UInt16                indexItem;
  297.     ItemReference        itemRef;
  298.     FlavorFlags            theFlags;
  299.  
  300.     if (gpFWXAppData->pSenderWindow != FrontWindow())
  301.         return false;
  302.         
  303.     //    loop through each item in the drag to make sure it has an HFS flavor
  304.     err = CountDragItems(theDrag, &numItems);
  305.     if (err == noErr) {
  306.         for (indexItem = 1; indexItem <= numItems; indexItem++) {
  307.  
  308.             err = GetDragItemReferenceNumber(theDrag, indexItem, &itemRef);
  309.  
  310.             if (err == noErr) {
  311.                 err = GetFlavorFlags(theDrag, itemRef, flavorTypeHFS, &theFlags );
  312.                 if (err != noErr)
  313.                     return false;    // drag item is not hfs, its all or nothing
  314.             } else
  315.                 return false;        // could not get item reference
  316.         }
  317.     } else {
  318.         return false;                // could not count items
  319.     }
  320.         
  321.     return true;                    // each item is an hfs (should always be that way)
  322. }
  323.  
  324. //////////////////////////////////////////////////////////////////////////////
  325. //
  326. //    HandleDragTracking
  327. //
  328. //    Called by the drag manager whenever a drag is
  329. //    over one of our windows. On entry the current
  330. //    port has been set to our windows by the Drag Manager.
  331. //
  332.  
  333. static pascal OSErr HandleDragTracking (
  334.     DragTrackingMessage        theMessage,
  335.     WindowPtr                pWin,
  336.     void                    *handlerRefCon,
  337.     DragReference            theDrag)
  338. {
  339. //#pragma unused handlerRefCon
  340.     WindowDataPtr            pWinData;
  341.     RgnHandle                hOldClip;
  342.     Rect                    iconRect, textRect, drawRect;
  343.     Point                    localPt;
  344.     SInt16                    mouseInWhichSpace;
  345.     SInt16                    deltaH, deltaV;
  346.     OSErr                    err = noErr;
  347.     
  348.     switch (theMessage)
  349.     {    
  350.         case kDragTrackingEnterHandler:            
  351.             // Initialization for the handler
  352.             (gpFWXAppData->dragHandlerGlobals).acceptableDragFlag = 
  353.                 DragItemsAreAcceptable(theDrag);
  354.             (gpFWXAppData->dragHandlerGlobals).hilitedSpace = kNoSpace;
  355.             HandleDragHilite(kHiliteInit, &iconRect, &textRect);
  356.             
  357.             // let the drag manager know if we can't accept this drag
  358.             if (!(gpFWXAppData->dragHandlerGlobals).acceptableDragFlag)
  359.                 err = dragNotAcceptedErr;
  360.             break;
  361.             
  362.         case kDragTrackingEnterWindow: 
  363.         case kDragTrackingInWindow:
  364.         case kDragTrackingLeaveWindow:            
  365.             // Handle highlighting the receive node icon
  366.             if (gpFWXAppData->dragHandlerGlobals.acceptableDragFlag)
  367.             {
  368.                 pWinData = (WindowDataPtr) GetWRefCon(pWin);
  369.                 deltaH = GetControlValue(pWinData->hHScrollBar);
  370.                 deltaV = GetControlValue(pWinData->hVScrollBar);
  371.                 SetOrigin(deltaH, deltaV);
  372.                 GetClip(hOldClip = NewRgn());
  373.                 drawRect = pWin->portRect;
  374.                 drawRect.bottom -= kScrollBarAdjust;
  375.                 drawRect.right -= kScrollBarAdjust;
  376.                 ClipRect(&drawRect);
  377.                 
  378.                 // Unless the mouse is leaving the visible area of the
  379.                 // window, check if it's in the window's content region
  380.                 if (theMessage == kDragTrackingLeaveWindow)
  381.                     mouseInWhichSpace = kNoSpace;
  382.                 else
  383.                 {
  384.                     GetDragMouse(theDrag, &localPt, nil);
  385.                     GlobalToLocal(&localPt);
  386.                     mouseInWhichSpace = WhichRecvNode(pWin, localPt);
  387.                 }
  388.  
  389.                 // If the mouse's space is not equal to the hilitedSpace
  390.                 // and the mouse is in a space  (i.e., a new, different space.)
  391.                 if ((mouseInWhichSpace != gpFWXAppData->dragHandlerGlobals.hilitedSpace) &&
  392.                     (mouseInWhichSpace != kNoSpace))
  393.                 {
  394.                     if (gpFWXAppData->dragHandlerGlobals.hilitedSpace != kNoSpace)
  395.                     {        
  396.                         // There is a currently hilited space, unhilite it
  397.                         GetNodeDragRect (pWin,
  398.                                          gpFWXAppData->dragHandlerGlobals.hilitedSpace,
  399.                                          &iconRect,
  400.                                          &textRect);
  401.                         HandleDragHilite(kHiliteOff, &iconRect, &textRect);
  402.                     }
  403.  
  404.                     // draw the hilight
  405.                     GetNodeDragRect(pWin, mouseInWhichSpace, &iconRect, &textRect);
  406.                     HandleDragHilite(kHiliteOn, &iconRect, &textRect);
  407.                     gpFWXAppData->dragHandlerGlobals.hilitedSpace = mouseInWhichSpace;                    
  408.                 }
  409.                 // else if the mouse is not in the content region
  410.                 // and an icon is hilighted, erase the hilight
  411.                 else if ((mouseInWhichSpace == kNoSpace) &&
  412.                          (gpFWXAppData->dragHandlerGlobals.hilitedSpace != kNoSpace))
  413.                 {
  414.                     GetNodeDragRect (pWin,
  415.                                      gpFWXAppData->dragHandlerGlobals.hilitedSpace,
  416.                                      &iconRect,
  417.                                      &textRect);
  418.                     HandleDragHilite(kHiliteOff, &iconRect, &textRect);
  419.                     gpFWXAppData->dragHandlerGlobals.hilitedSpace = kNoSpace;
  420.                 }
  421.                 SetOrigin(0, 0);
  422.                 SetClip(hOldClip);
  423.                 DisposeRgn(hOldClip);
  424.             }
  425.             break;
  426.  
  427.         // do nothing for the leaveHandler message
  428.         case kDragTrackingLeaveHandler:
  429.             HandleDragHilite(kHiliteDispose, &iconRect, &textRect);
  430.             break;
  431.         
  432.         // let the drag manager know if we didn't recognize the message
  433.         default:
  434.             err = paramErr;
  435.     }
  436.     return err;
  437. }
  438.  
  439. //////////////////////////////////////////////////////////////////////////////
  440. //
  441. //    HandleDragHilite
  442. //
  443. //    Handle hiliting of node icons in sender window
  444. static void HandleDragHilite (
  445.     SInt16                theMessage,
  446.     Rect                *iconRect,
  447.     Rect                *textRect)
  448. {
  449.     static Handle        hIconSuite;
  450.     OSErr                err;
  451.  
  452.     switch (theMessage)
  453.     {
  454.         case kHiliteInit:
  455.             err = GetIconSuite(&hIconSuite, kDropIconSuiteID, svAllAvailableData);
  456.             break;
  457.         case kHiliteOff:
  458.             err = PlotIconSuite(iconRect, atNone, ttNone, hIconSuite);
  459.             InvertRect(textRect);
  460.             break;
  461.         case kHiliteOn:
  462.             err = PlotIconSuite(iconRect, atNone, ttSelected, hIconSuite);
  463.             InvertRect(textRect);
  464.             break;
  465.         case kHiliteDispose:
  466.             err = DisposeIconSuite(hIconSuite, false);
  467.     }
  468. }
  469.  
  470. //////////////////////////////////////////////////////////////////////////////
  471. //
  472. //    HandleDragReceive
  473. //
  474. //    Called by the drag manager when a drag ends in our window
  475. //
  476. //    Need to loop through each drag item and get its hfs data
  477. //    building a list of fsspec's as we go.
  478. //
  479. //    Send an AppleEvent to ourselves to handle copying the list.
  480. //
  481.  
  482. static pascal OSErr HandleDragReceive (
  483.     WindowPtr                pWin,
  484.     void                    *handlerRefCon, 
  485.     DragReference            theDrag)
  486. {
  487. //#pragma unused handlerRefCon
  488.     
  489.     ItemReference            itemRef;
  490.     Size                    flavorDataSize;
  491.     FSSpecPtr                pFSSpecList;
  492.     HFSFlavor                itemHFSFlavor;
  493.     UInt16                    numItems;
  494.     UInt16                    indexItem;
  495.     OSErr                    err = noErr;
  496.     
  497.     if (! (DragItemsAreAcceptable(theDrag) && MouseIsInContentRgn(theDrag, pWin)))
  498.         return dragNotAcceptedErr;
  499.  
  500.     err = CountDragItems(theDrag, &numItems);
  501.     if (err == noErr)
  502.     {
  503.         //    allocate a buffer to grab each of the drag items FSSpecs
  504.         pFSSpecList = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numItems);
  505.         if (pFSSpecList == nil)
  506.             return memFullErr;
  507.         
  508.         for (indexItem = 1; indexItem <= numItems; indexItem++) {
  509.             // reset flavorDataSize through each loop
  510.             // as it gets updated by the GetFlavorData call
  511.             flavorDataSize = sizeof(HFSFlavor);
  512.             
  513.             err = GetDragItemReferenceNumber(theDrag, indexItem, &itemRef);
  514.             if (err != noErr) {
  515.                 DisposePtr((Ptr)pFSSpecList);
  516.                 return err;
  517.             }
  518.             
  519.             err = GetFlavorData(theDrag, itemRef, flavorTypeHFS, 
  520.                                 &itemHFSFlavor, &flavorDataSize, 0);
  521.             if (err != noErr) {
  522.                 DisposePtr((Ptr)pFSSpecList);
  523.                 return err;
  524.             }
  525.             pFSSpecList[indexItem-1] = itemHFSFlavor.fileSpec;
  526.         }
  527.         if (err == noErr)
  528.             SendDropInWindowRecvNode(pWin, theDrag, pFSSpecList, numItems);
  529.  
  530.         DisposePtr((Ptr)pFSSpecList);
  531.     }
  532.     return err;
  533. }
  534.  
  535. //////////////////////////////////////////////////////////////////////////////
  536. //
  537. //    SendSetterToSelf
  538. //
  539. //    Send an AppleEvent to ourself with the firewire file exchange
  540. //    receive node ID and the FSSpec list of items to be sent.
  541. //
  542.  
  543. OSErr SendFSSpecListToSelf (
  544.     FWXNodeID                fwxNodeID,
  545.     FSSpecPtr                pFSSpecList,
  546.     UInt16                    numFSSpecs)
  547. {
  548.     AppleEvent                send;
  549.     AppleEvent                reply;
  550.     AEDesc                    selfTarget;
  551.     ProcessSerialNumber        psn;
  552.     UInt32                    longFSSpecCount;
  553.     OSErr                    err;
  554.  
  555.     longFSSpecCount = numFSSpecs;
  556.     selfTarget.dataHandle = nil;
  557.     send.dataHandle = nil;
  558.  
  559.     GetCurrentProcess(&psn);
  560.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &selfTarget);
  561.     if (err != noErr)
  562.         return err;
  563.     
  564.     err = AECreateAppleEvent(kAEFWXEventClass, kAEFileSpecList, &selfTarget, 
  565.             kAutoGenerateReturnID, kAnyTransactionID, &send);
  566.     if (err != noErr) {
  567.         AEDisposeDesc(&selfTarget);
  568.         return err;
  569.     }
  570.         
  571.     err = AEPutParamPtr(&send, kAEFWXNodeIDKey, kAEFWXNodeIDType, (Ptr) &fwxNodeID, sizeof(FWXNodeID));
  572.     if (err != noErr) {
  573.         AEDisposeDesc(&selfTarget);
  574.         if (send.dataHandle != nil)
  575.             AEDisposeDesc(&send);
  576.         return err;
  577.     }
  578.  
  579.     err = AEPutParamPtr(&send, kAEFSSpecKey, typeFSS, (Ptr) pFSSpecList, sizeof(FSSpec)*numFSSpecs);
  580.     if (err != noErr) {
  581.         AEDisposeDesc(&selfTarget);
  582.         if (send.dataHandle != nil)
  583.             AEDisposeDesc(&send);
  584.         return err;
  585.     }
  586.     
  587.     err = AEPutParamPtr(&send, kAEFSSpecCountKey, typeLongInteger, (Ptr) &longFSSpecCount, sizeof(UInt32));
  588.     if (err != noErr) {
  589.         AEDisposeDesc(&selfTarget);
  590.         if (send.dataHandle != nil)
  591.             AEDisposeDesc(&send);
  592.         return err;
  593.     }
  594.  
  595.     err = AESend(&send, &reply, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer,
  596.                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  597.  
  598.     if (err != noErr) {
  599.         AEDisposeDesc(&selfTarget);
  600.         AEDisposeDesc(&send);
  601.     }
  602.  
  603.     return err;
  604. }
  605.  
  606. //////////////////////////////////////////////////////////////////////////////
  607. //
  608. //    GetNodeInfo
  609. //
  610. //    Return the nodeInfo record for the node id.
  611. //
  612.  
  613. OSErr GetNodeInfo (
  614.     FWXNodeID            nodeID,
  615.     RecvNodePtr            *pRecvNode)
  616. {
  617.     WindowPtr            pWin;
  618.     WindowDataPtr        pWinData;
  619.     RecvNodePtr            pTempRecvNode;
  620.     SInt16                index;
  621.     OSErr                err = noErr;
  622.     
  623.     pWin = gpFWXAppData->pSenderWindow;
  624.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  625.         
  626.     pTempRecvNode = pWinData->pRecvNodeList;
  627.     for (index = 0; index < pWinData->numRecvNodes; index++) {
  628.         if (pTempRecvNode->nodeID == nodeID)
  629.             break;
  630.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  631.     }
  632.  
  633.     *pRecvNode = pTempRecvNode;
  634.     if (pTempRecvNode == nil)
  635.         err = resNotFound;     // JKL *** what error?
  636.  
  637.     return err;
  638. }
  639.  
  640.  
  641. //////////////////////////////////////////////////////////////////////////////
  642. //
  643. //    GetNodeName
  644. //
  645. //    Get the bounding rectangle of a drag area for the specified index.
  646. //    There is a drag area for each FireWire Exchange node.
  647. //
  648.  
  649. OSErr GetNodeName (
  650.     WindowPtr            pWin,
  651.     SInt16                nodeIndex,
  652.     StringPtr            *pString)
  653. {
  654.     WindowDataPtr        pWinData;
  655.     RecvNodePtr            pTempRecvNode;
  656.     SInt16                index;
  657.     
  658.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  659.     if (nodeIndex > pWinData->numRecvNodes)
  660.         return memFullErr;        // JKL - some error
  661.         
  662.     pTempRecvNode = pWinData->pRecvNodeList;
  663.     for (index = 1; index < nodeIndex; index++) {
  664.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  665.     }
  666.  
  667.     *pString = pTempRecvNode->nodeName;
  668.  
  669.     return noErr;
  670. }
  671.  
  672.  
  673. //////////////////////////////////////////////////////////////////////////////
  674. //
  675. //    GetNodeDragRect
  676. //
  677. //    Get the bounding rectangle of a drag area for the specified index.
  678. //    There is a drag area for each FireWire Exchange node.
  679. //
  680.  
  681. OSErr GetNodeDragRect (
  682.     WindowPtr            pWin,
  683.     SInt16                nodeIndex,
  684.     Rect                *iconRect,
  685.     Rect                *textRect)
  686. {
  687.     WindowDataPtr        pWinData;
  688.     RecvNodePtr            pTempRecvNode;
  689.     SInt16                index;
  690.     
  691.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  692.     if (nodeIndex > pWinData->numRecvNodes)
  693.         return memFullErr;        // JKL - some error
  694.         
  695.     pTempRecvNode = pWinData->pRecvNodeList;
  696.     for (index = 1; index < nodeIndex; index++) {
  697.         pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  698.     }
  699.  
  700.     *iconRect = pTempRecvNode->recvNodeIconRect;
  701.     *textRect = pTempRecvNode->recvNodeTextRect;
  702.  
  703.     return noErr;
  704. }
  705.  
  706.  
  707. //////////////////////////////////////////////////////////////////////////////
  708. //
  709. //    WhichRecvNode
  710. //
  711. //    Determine where the drop has taken place. There is a space for each
  712. //    FireWire Exchange node. After doing a compare it will return the space
  713. //    number, or kNoSpace if it didn't land in a space.
  714. //
  715.  
  716. SInt16 WhichRecvNode (
  717.     WindowPtr            pWin,
  718.     Point                localPt)
  719. {
  720.     WindowDataPtr        pWinData;
  721.     RgnHandle            iconRgn, textRgn, dragRgn;
  722.     Rect                iconRect;
  723.     Rect                textRect;
  724.     SInt16                count;
  725.     SInt16                theNodeIndex;
  726.     
  727.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  728.     theNodeIndex = kNoSpace;
  729.     if (pWinData == nil)
  730.         return theNodeIndex;
  731.     
  732.     iconRgn = NewRgn();
  733.     textRgn = NewRgn();
  734.     dragRgn = NewRgn();
  735.     if (pWinData != nil)
  736.     {
  737.         for (count = 1; count <= pWinData->numRecvNodes; count ++)
  738.         {            
  739.             GetNodeDragRect(pWin, count, &iconRect, &textRect);
  740.             RectRgn(iconRgn, &iconRect);
  741.             RectRgn(textRgn, &textRect);
  742.             UnionRgn(iconRgn, textRgn, dragRgn);
  743.             if (PtInRgn(localPt, dragRgn))
  744.             {
  745.                 theNodeIndex = count;
  746.                 break;
  747.             }
  748.         }
  749.     }
  750.     DisposeRgn(iconRgn);
  751.     DisposeRgn(textRgn);
  752.     DisposeRgn(dragRgn);
  753.     return theNodeIndex;
  754. }
  755.  
  756. //////////////////////////////////////////////////////////////////////////////
  757. //
  758. //    GetNodeIDFromIndex
  759. //
  760. //    Using an index into the list of receive nodes, get the FireWire File
  761. //    Exchange node id from the indexed node.
  762. //
  763.  
  764. static void GetNodeIDFromIndex(
  765.     SInt16                nodeIndex,
  766.     FWXNodeID            *whichNode,
  767.     WindowPtr            pWin)
  768. {
  769.     WindowDataPtr        pWinData;
  770.     RecvNodePtr            pTempRecvNode;
  771.     SInt16                i;
  772.     
  773.     pWinData = (WindowDataPtr) GetWRefCon(pWin);
  774.     *whichNode = (FWXNodeID) kInvalidFWXNodeID;
  775.     
  776.     if (pWinData != nil) {
  777.         
  778.         if (nodeIndex <= pWinData->numRecvNodes) {
  779.             pTempRecvNode = pWinData->pRecvNodeList;
  780.             for (i = 1; i < nodeIndex; i++) {
  781.                 pTempRecvNode = (RecvNodePtr) pTempRecvNode->pNextNode;
  782.             }
  783.     
  784.             *whichNode = pTempRecvNode->nodeID;
  785.         }
  786.     }
  787. }
  788.         
  789. //////////////////////////////////////////////////////////////////////////////
  790. //
  791. //    SendDropInWindowRecvNode
  792. //
  793. //    Get the drag location, convert it to local coordinates. Find which receive
  794. //    node the drop occurred in and send us an AppleEvent with the list of FSSpec's.
  795. //
  796.  
  797. static void SendDropInWindowRecvNode (
  798.     WindowPtr            pWin,
  799.     DragReference        theDrag,
  800.     FSSpecPtr            pFSSpecList,
  801.     UInt16                numInList)
  802. {
  803.     Point                 thePoint;
  804.     GrafPtr                oldPort;
  805.     FWXNodeID            whichFWXNode = (FWXNodeID) kInvalidFWXNodeID;
  806.     SInt16                theNodeIndex;
  807.     OSErr                err;
  808.  
  809.     GetPort(&oldPort);
  810.     SetPort(pWin);
  811.     GetDragMouse(theDrag, &thePoint, 0L);
  812.     GlobalToLocal(&thePoint);
  813.     theNodeIndex = WhichRecvNode(pWin, thePoint);
  814.     SetPort(oldPort);
  815.     
  816.     if (theNodeIndex != kNoSpace)
  817.         GetNodeIDFromIndex(theNodeIndex, &whichFWXNode, pWin);
  818.  
  819.     if (whichFWXNode != (FWXNodeID) kInvalidFWXNodeID)
  820.         err = SendFSSpecListToSelf(whichFWXNode, pFSSpecList, numInList);
  821. }
  822.  
  823. //////////////////////////////////////////////////////////////////////////////
  824. //
  825. //    HandleAEFileSpecList
  826. //
  827. //    Pull parameters out of AppleEvent and call routine to handle the drop.
  828. //
  829.  
  830. pascal OSErr HandleAEFileSpecList (
  831.     AppleEvent            *pAEvent,
  832.     AppleEvent             *pReply,
  833.     SInt32                refCon)
  834. {
  835. //#pragma unused pReply
  836. //#pragma unused refCon
  837.  
  838.     OSErr                err;
  839.     DescType            returnType;
  840.     Size                returnSize;
  841.     FWXNodeID            whichNode;
  842.     UInt32                numFSSpecs;
  843.     FSSpecPtr            pFSSpec;
  844.     UInt16                index;
  845.  
  846.     err = AEGetParamPtr(pAEvent, kAEFWXNodeIDKey, kAEFWXNodeIDType, &returnType,
  847.                         (Ptr) &whichNode, sizeof(FWXNodeID), &returnSize);
  848.     if (err != noErr)
  849.         return err;
  850.  
  851.     err = AEGetParamPtr(pAEvent, kAEFSSpecCountKey, typeLongInteger, &returnType,
  852.                         (Ptr) &numFSSpecs, sizeof(SInt32), &returnSize);
  853.     if (err != noErr)
  854.         return err;
  855.  
  856.     pFSSpec = (FSSpecPtr) NewPtr(sizeof(FSSpec) * numFSSpecs);
  857.     if (pFSSpec == nil)
  858.         return memFullErr;
  859.         
  860.     err = AEGetParamPtr(pAEvent, kAEFSSpecKey, typeFSS, &returnType,
  861.                         (Ptr) pFSSpec, sizeof(FSSpec) * numFSSpecs, &returnSize);
  862.     if (err != noErr)
  863.         return err;
  864.  
  865.     for (index = 0; index < numFSSpecs; index++) {
  866.         err = HandleFSItem(&pFSSpec[index], whichNode);
  867.         if (err != noErr) {
  868.             sprintf(debugStr, "Error in HandleFileList: %d", err);
  869.             FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  870.             break;
  871.         }
  872.     }
  873.     
  874.     DisposePtr((Ptr) pFSSpec);
  875.     
  876.     return err;
  877. }
  878.